package me.keiwu.user.service.impl;

import me.keiwu.pub.data.Response;
import me.keiwu.pub.util.EntityUtil;
import me.keiwu.user.dao.CombAvatarDao;
import me.keiwu.user.dao.ItemDao;
import me.keiwu.user.dao.CombAvatarSettingDao;
import me.keiwu.user.dao.UserItemDao;
import me.keiwu.user.domain.CombAvatar;
import me.keiwu.user.domain.Item;
import me.keiwu.user.domain.User;
import me.keiwu.user.domain.UserItem;
import me.keiwu.user.domain.CombAvatarSetting;
import me.keiwu.user.service.ItemService;
import me.keiwu.user.service.UserMiscService;
import me.keiwu.user.service.UserService;
import me.keiwu.user.util.ExceptionUtil;
import me.keiwu.user.util.enums.ItemType;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by kei on 25/11/2017.
 */
@Service
@Transactional
public class ItemServiceImpl implements ItemService {

    private Logger logger = LoggerFactory.getLogger(ItemServiceImpl.class);

    @Autowired
    private ItemDao itemDao;
    @Autowired
    private UserItemDao userItemDao;
    @Autowired
    private CombAvatarDao combAvatarDao;
    @Autowired
    private CombAvatarSettingDao combAvatarSettingDao;
    @Autowired
    private UserService userService;
    @Autowired
    private UserMiscService userMiscService;
    @Autowired
    private ExceptionUtil exceptionUtil;


    @Override
    public Page<Item> getShelveItems(Long userId, int page, int size) {
        Sort sort = new Sort(Sort.Direction.ASC, "createdTime");
        Pageable pageable = new PageRequest(page, size, sort);
        Page<Item> items = itemDao.findAll(this.getShelveItemListSpec(), pageable);
        CombAvatarSetting setting = combAvatarSettingDao.findOne(userId);
        for (Item item : items) {
            int count = userItemDao.countAllByUserIdAndItemIdAndIsDelFalse(userId, item.getId());
            if (count > 0) item.setGet(true);
            if (setting != null && (item.getId().equals(setting.getSingleId())
                    || item.getId().equals(setting.getSuitId()))) {
                item.setSet(true);
            } else {
                item.setSet(false);
            }
        }
        return items;
    }

    @Override
    public Page<Item> getShelveItems(int page, int size) {
        Sort sort = new Sort(Sort.Direction.ASC, "createdTime");
        Pageable pageable = new PageRequest(page, size, sort);
        return itemDao.findAll(this.getShelveItemListSpec(), pageable);
    }

    private Specification<Item> getShelveItemListSpec() {
        return (root, query, cb) -> {
            Predicate p1 = cb.equal(root.get("isDel"), false);
            Predicate p2 = cb.equal(root.get("shelve"), true);
            return cb.and(p1, p2);
        };
    }


    @Override
    public Page<Item> getAllSuits(int page, int size) {
        Sort sort = new Sort(Sort.Direction.ASC, "createdTime");
        Pageable pageable = new PageRequest(page, size, sort);
        Specification<Item> spec = (root, query, cb) -> {
            Predicate p1 = cb.equal(root.get("itemType"), ItemType.SUIT.getType());
            Predicate p2 = cb.equal(root.get("isDel"), false);
            return cb.and(p1, p2);
        };
        return itemDao.findAll(spec, pageable);
    }


    @Override
    public Page<Item> getAllSingles(int page, int size) {
        Sort sort = new Sort(Sort.Direction.ASC, "createdTime");
        Pageable pageable = new PageRequest(page, size, sort);
        Specification<Item> spec = (root, query, cb) -> {
            Predicate p1 = cb.equal(root.get("itemType"), ItemType.SINGLE.getType());
            Predicate p2 = cb.equal(root.get("isDel"), false);
            return cb.and(p1, p2);
        };
        // 单件要获取所有和套装的组合形象，不存在要构造一个
        Page<Item> singleList = itemDao.findAll(spec, pageable);
        List<Item> suitList = itemDao.findAllByItemTypeAndIsDelFalse(ItemType.SUIT.getType());

        singleList.forEach(single -> {
            List<CombAvatar> combAvatars = new ArrayList<>();
            for (Item suit : suitList) {
                CombAvatar avatar = combAvatarDao.findBySuitIdAndSingleId(suit.getId(), single.getId());
                if (avatar == null) {
                    avatar = new CombAvatar();
                    avatar.setSingleId(single.getId());
                    avatar.setSuitId(suit.getId());
                }
                combAvatars.add(avatar);
            }
            single.setCombAvatars(combAvatars);
        });
        return singleList;
    }

    @Override
    public Integer calcUserLevel(Long userId) {
        return userItemDao.countAllByUserIdAndItemTypeAndIsDelFalse(userId, ItemType.SINGLE.getType());
    }

    @Override
    public Response exchangeItem(Long userId, Integer itemId) {
        Item item = itemDao.findOne(itemId);
        if (item == null || item.isDel() || !item.isShelve() || item.isShareGet()) {
            return Response.fail("不存在该商品或者商品已下架");
        }

        UserItem userItem = userItemDao.findByUserIdAndItemId(userId, itemId);
        if (userItem != null && !userItem.isDel()) {
            return Response.fail("已经拥有该商品");
        }

        User user = userService.getUserById(userId);
        if (userService.changeGold(user, -Math.abs(item.getCostGold()))) {
            return this.saveUserItem(user, item, userItem);
        }
        return Response.fail("星币不足");
    }


    private Response saveUserItem(User user, Item item, UserItem userItem) {
        if (userItem == null) {
            userItem = new UserItem();
            userItem.setUserId(user.getId());
            userItem.setItemId(item.getId());
            userItem.setItemType(item.getItemType());
        }
        userItem.setDel(false);
        userItemDao.save(userItem);

        // 套装要自动设置基础形象
        if (ItemType.SUIT.getType() == item.getItemType()) {
            CombAvatarSetting setting = combAvatarSettingDao.findOne(user.getId());
            if (setting == null) {
                setting = new CombAvatarSetting();
                setting.setUserId(user.getId());
            }
            setting.setSuitId(item.getId());
            setting.setSingleId(null);
            combAvatarSettingDao.save(setting);

            user.setAvatarUrl(item.getImgUrl());
            user.setLevel(this.calcUserLevel(user.getId()));
            userService.save(user);
            return Response.ok(user.getAvatarUrl());
        }
        return Response.ok();
    }


    @Override
    public Response setCombAvatar(Long userId, Integer suitId, Integer singleId) {
        if (suitId == null || singleId == null) return Response.fail("参数错误");
        CombAvatar combAvatar = combAvatarDao.findBySuitIdAndSingleId(suitId, singleId);
        if (combAvatar != null) {
            User user = userService.getUserById(userId);
            CombAvatarSetting setting = combAvatarSettingDao.findOne(user.getId());
            if (setting == null) {
                setting = new CombAvatarSetting();
                setting.setUserId(userId);
            }
            setting.setSuitId(suitId);
            setting.setSingleId(singleId);
            combAvatarSettingDao.save(setting);

            user.setAvatarUrl(combAvatar.getImgUrl());
            userService.save(user);
            return Response.ok(user.getAvatarUrl());
        }
        logger.error("not found comb avatar，suitId={}, singleId={}", suitId, singleId);
        exceptionUtil.logError(this.getClass(), "setCombAvatar", "not found comb avatar!");
        return Response.fail("没有该ip形象组合，更换形象失败");
    }


    @Override
    public Response setCombAvatar(Long userId, Integer singleId) {
        if (singleId == null) return Response.fail("参数错误");
        User user = userService.getUserById(userId);
        CombAvatarSetting setting = combAvatarSettingDao.findOne(user.getId());
        if (setting == null) return Response.fail("没有设置基础套装");

        CombAvatar combAvatar = combAvatarDao.findBySuitIdAndSingleId(setting.getSuitId(), singleId);
        if (combAvatar != null) {
            setting.setSingleId(singleId);
            combAvatarSettingDao.save(setting);

            user.setAvatarUrl(combAvatar.getImgUrl());
            userService.save(user);
            return Response.ok(user.getAvatarUrl());
        }
        logger.error("not found comb avatar!, singleId={}", singleId);
        exceptionUtil.logError(this.getClass(), "setCombAvatar", "not found comb avatar!");
        return Response.fail("没有该ip形象组合，更换形象失败");
    }


    @Override
    public Item addSuit(String name, String imgUrl, String itemDetail, int costGold,
                        boolean shareGet, boolean shelve) {
        Item item = new Item();
        item.setName(name);
        item.setImgUrl(imgUrl);
        item.setItemDetail(itemDetail);
        item.setCostGold(costGold);
        item.setItemType(ItemType.SUIT.getType());
        item.setShelve(shelve);
        item.setShareGet(shareGet);
        itemDao.save(item);
        return item;
    }

    @Override
    public Item updateSuit(Integer itemId, String name, String imgUrl, String itemDetail, int costGold,
                           boolean shareGet, boolean shelve) {
        Item dbItem = itemDao.findOne(itemId);
        if (dbItem == null) return null;
        Item item = new Item();
        item.setId(itemId);
        item.setName(name);
        item.setImgUrl(imgUrl);
        item.setItemDetail(itemDetail);
        item.setCostGold(costGold);
        item.setItemType(ItemType.SUIT.getType());
        item.setShelve(shelve);
        item.setShareGet(shareGet);
        // 空的不更新
        EntityUtil.copyNonBlankProperties(item, dbItem);
        itemDao.save(dbItem);
        return dbItem;
    }



    @Override
    public Item addSingle(String name, String imgUrl, int costGold, boolean shareGet,
                          boolean shelve, List<CombAvatar> combAvatarList) {
        // 插入单件，要同步插入n个套装相关的combAvatar
        List<Item> suitList = itemDao.findAllByItemTypeAndIsDelFalse(ItemType.SUIT.getType());
        if (suitList.size() != combAvatarList.size()) return null;

        Item item = new Item();
        item.setName(name);
        item.setImgUrl(imgUrl);
        item.setCostGold(costGold);
        item.setItemType(ItemType.SINGLE.getType());
        item.setShelve(shelve);
        item.setShareGet(shareGet);
        itemDao.save(item);

        combAvatarList.forEach(ca -> ca.setSingleId(item.getId()));
        combAvatarDao.save(combAvatarList);
        item.setCombAvatars(combAvatarList);
        return item;
    }

    @Override
    public Item updateSingle(Integer itemId, String name, String imgUrl, int costGold, boolean shareGet,
                             boolean shelve, List<CombAvatar> combAvatarList) {
        // 更新单件，要同步更新n个套装相关的combAvatar
        List<Item> suitList = itemDao.findAllByItemTypeAndIsDelFalse(ItemType.SUIT.getType());
        if (suitList.size() != combAvatarList.size()) return null;
        combAvatarDao.save(combAvatarList);

        Item dbItem = itemDao.findOne(itemId);
        if (dbItem == null) return null;
        Item item = new Item();
        item.setId(itemId);
        item.setName(name);
        item.setImgUrl(imgUrl);
        item.setCostGold(costGold);
        item.setItemType(ItemType.SINGLE.getType());
        item.setShelve(shelve);
        item.setShareGet(shareGet);
        item.setCombAvatars(combAvatarList);
        // 空的不更新
        EntityUtil.copyNonBlankProperties(item, dbItem);
        itemDao.save(dbItem);
        return dbItem;
    }


    @Override
    public Item shelveItem(Integer itemId, boolean shelve) {
        Item item = itemDao.findOne(itemId);
        if (item == null) return null;
        item.setShelve(shelve);
        return item;
    }


    public static void main(String[] args) {
        System.err.println(RandomStringUtils.randomAlphanumeric(16));
    }


}
